Each LScript that you select for execution is automatically filtered through the preprocessor, whether or not it contains any preprocessor-specific instructions or commands. The preprocessor is simply part of the process of compiling a script for execution.
All preprocessor directives in an LScript begin with an AT sign ('@
') in
column 1, followed by the directive name. For example:
// A simple script to rotate an object @warnings ...In older versions of LScript, the
#pragma
keyword was employed to provide
some of this functionality, and it can still appear in LScript files. However, it has
become obsolete, and support for it will be dropped in a future release of the LScript
engine. It's use is therefore discouraged.The following compiler directives are recognized by the LScript preprocessor:
warnings [count] The warnings directive instructs LScript to bypass the display of run-time warning messages. The optional count parameter is an integer value that indicates the maximum number of warnings that will be displayed. Warning messages could be generated when a loss of data or an unusual programming circumstance is detected by the LScript engine during script execution. For instance, assigning the return values of a user-defined procedure to an array whose size is less than the count of return arguments is always guaranteed to generate a warning message during an LScript execution. Warnings are turned off automatically in compiled scripts. errors count The errors directive provides to LScript the maximum number of run-time error messages that will be displayed. The count parameter is an integer value, and must be provided. Error messages cannot be turned off, and the count parameter cannot be zero (0). Error messages are enabled in compiled scripts. unused During script development, it's possible to clutter your script with unused variables. In large scripts, it can take a great deal of time to locate and purge these "dead" variables. The unused directive causes LScript to detect and report on declared variables that are never used (i.e., assigned a value). When your script has completed execution, LScript will display a dialog window for each variable that it determined to be unused. This directive is intended as a support feature when the strict directive is enabled, and then only as a cleanup measure when script development is nearing completion. It is not supported in compiled scripts nor in "lax" declaration mode. version {major.minor | "major.minor"} The LScript engine provides for allowing scripts to specify minimum versions of the LScript plug-in to be used to execute the script. This is useful for scripts that have taken advantage of newer features that would cause the script to fail to compile on earlier versions of the plug-in. Version indicators can be either literal floating-point values, or literal string values. Only major and minor values, separated by a period ('.'), will be considered valid by the interpreter. autoerror The normal practice for the LScript engine is to provide the return value of all Layout- or Modeler-specific commands and functions to the script. This allows the script to determine if a command failed, and take actions that it deems appropriate. However, there may be situations where the script programmer does not care to add the extra code required to manage these potential error conditions. In this case, the script programmer can specify the autoerror directive. This directive instructs LScript to handle these error conditions automatically, by issuing an error message to the user, and terminating the script. asyncspawn LScript has the ability to launch external processes during a script's execution (see the example LScript batch.ls for an illustration of this capability). The default behavior of the LScript engine is to execute these processes in a synchronous fashion (i.e., halting execution of the LScript until the external process has completed). However, there may be times when a script programmer wishes to interact with an external process. In this case, the script programmer needs to direct LScript to launch external processes asynchronously, causing them to operate in parallel with the LScript. The asyncspawn directive is used in this situation. nonrandom The nonrandom directive will disable the random access to ASCII text file lines that LScript affords to script programmers through the use of its line() File Object Agent method. When specified, LScript will not preprocess text files (those opened in ASCII mode) to determine line offsets. Attempts to access the line() method in a script where this pragma is employed will result in a run-time error. If your script tends to deal with large text files without the need to randomly access lines, utilizing this directive will appreciably increase the overall execution speed of your script. literalpaths Because LScript operates across (currently) three very-different operating systems, it will automatically attempt to massage file paths provided to functions suchs as matchfiles() and getfile() into something more suitable for the current operating system. For instance, under the Macintosh OS, UNIX forward slashes (/) and MS-DOS back slashes (\) are converted into colons (:) because that is the standard used by the Mac to separate directories. The literalpaths directive disables this internal processing, and causes the LScript engine to use file paths as they appear in the script. strict LScript allows you to simply use variables and arrays whereever and whenever you need them without having to explicitly declare them in a previous 'var' statement (and in the case of arrays, without having had to first explicitly declare an upper limit). However, there may be times when you wish to add more structure to your script development by requiring all variables and arrays to be explicitly declared. The strict directive switches the LScript engine into a behavior where variables and arrays are required to be explicitly declared or sized in a var statement. Regardless of the current declaration mode, multi-dimensional arrays must always be explicitly declared.
Insert files are used to house common commands and code that you wish to make availble to two or more LScripts. This prevents you from not only having to duplicate script code across all LScripts sharing the insert file, but greatly reduces the likelihood that you will alter the functionality or meaning of data as you duplicate it. Housing common code in an insert file also provides the advantage that updates can be performed just once to all dependent scripts, in a single location.
You can insert files into your original scripts (and into other insert files, for that
matter, up to 30 levels deep!) by using the insert
directive
followed by a string literal that specifies the name of the file to be inserted:
... @insert "myinc.lsi" ...If an insert file does not contain an absolute path, the LScript preprocessor will attempt to locate the script using the following steps:
1. Look in the current directory (which may or may not be the same location as the script being executed) 2. Look in each directory specified in the LibPath configuration elementIf an insert file cannot be located, the LScript preprocessor will halt with an error message, and the LScript engine will terminate.
Preprocessor directives continue to be evaluated and accumulated as each insert file is processed.
The LScript preprocessor imposes no naming conventions on your include files. They
can be named in any fashion you wish, as long as the names are accurately provided
to the insert
directive.
SELECT_SPHERE
" is a bit easier
to understand than "566
").Macros can also be embedded, which means that if a macro identifier appears in the value of another macro identifier, then a substitution will take place on the embedded identifier before the main identifier is substituted in the script code.
Preprocess macros are defined using the define
directive, followed
by the macro identifier name and the value to be assigned to that identifier:
... @define TOTAL_LIGHTS 100 ...In the above example, the identifier "
TOTAL_LIGHTS
" is assigned a value of
100. If this identifier is encountered anywhere in the script code (or within code found
in a file inserted after the definition), the LScript preprocessor will substitute the
value in the output code before passing it to the LScript engine to be compiled.
Therefore, if the following line of script code were processed after the definition of
TOTAL_LIGHTS
:
... for(x = 0;x < TOTAL_LIGHTS;x++) ...the LScript engine would actually see:
... for(x = 0;x < 100;x++) ...Macro substitution occurs in the preprocessor before any other processing takes place.
Let's see an example of this. If the following line of code were passed to a traditional preprocessor (for instance, a C preprocessor), a compile-time error would occur because the embedded identifier does not exist in a context wherein it can be consider stand-alone (in other words, it is part of another identifier, and becomes therefore inelligible):
#define ONEFIFTY 15 ... x = ONEFIFTY0; // <--- error! no such identifier "ONEFIFTY0"However, LScript's preprocessor would handle the situation differently:
@define ONEFIFTY 15 ... x = ONEFIFTY0; // <--- assigns the value 150 to xThis method of high-visibility substitution can be powerful, but can also cause you many difficulties if you happen to use script variable and function identifiers that contain embedded macro names. Please keep this in mind while writing your LScripts.
@define SELECT 15 @define SELECT2 string("SELECT ",SELECT0) @define SELECT3 "Bob!" @define VERSION_DIRECTIVE version 1.0 @define BEGIN_BOBS_MAIN main { @define END_BOBS_MAIN } @define REM // @insert "includes.h" @VERSION_DIRECTIVE @warnings BEGIN_BOBS_MAIN info(SELECT2); REM prints "SELECT 150" info(SELECT2 + SELECT3); REM using string math, prints "SELECT 150Bob!" END_BOBS_MAIN